/**
 * @description: 钉钉授权登录及用户信息获取 service
 * @version: 0.0.1
 * @author: z..
 * @Date: 2023-06-12 18:16:39
 */

import { Config } from '@midwayjs/decorator';
import { Provide, Inject, httpError } from '@midwayjs/core';
import { ApiDingtalk } from '../utils/api.dingtalk';
import { OapiDingtalk } from '../utils/oapi.dingtalk';
import { SendDingtalkMsgService } from "./send.dingtalk.msg.service";

import { RobotAlarmRecordsModel } from "../entity/robot_alarm_records.method";
import { RobotAlarmLogsModel } from "../entity/robot_alarm_logs.method"

import { Context } from '@midwayjs/koa';
const moment = require('moment');

@Provide()
export class DingtalkRobotService {

  @Config('dingtalkAuthConfig')
  dingtalkAuthConfig: any;

  @Config('appConfig')
  appConfig: any;

  @Inject()
  ctx: Context;

  @Inject()
  ApiDingtalk: ApiDingtalk;

  @Inject()
  OapiDingtalk: OapiDingtalk;

  @Inject()
  RobotAlarmRecordsModel: RobotAlarmRecordsModel;

  @Inject()
  SendDingtalkMsgService: SendDingtalkMsgService;

  @Inject()
  RobotAlarmLogsModel: RobotAlarmLogsModel;

  /**
   * 任务通知分页查询
   * @param {*} pageSize 
   * @param {*} pageNum 
   * @param {*} searchKey 
   */
  async getAlarmPage(params: any): Promise<any> {
    const { ctx } = this;
    const total = await this.RobotAlarmRecordsModel.getTotalNum(params);
    let res = {
      total: total[0].num,
      lists: [],
      id: ctx.unionId
    }
    if (total[0].num) {
      const resList = await this.RobotAlarmRecordsModel.getDataByPage(params);
      res.lists = resList;
    }
    return res;
  }

  /**
   * 新增任务通知
   * @param {*} alarmName 
   * @param {*} alarmContent 
   * @param {*} alarmType 
   * @param {*} alarmTime 
   * @param {*} alarmEndtime 
   * @param {*} alarmUserid
   * @param {*} alarmInner 
   * @param {*} alarmStatus 状态 未开始NOT_START,进行中START,报警成功SUCCESS,报警失败FAIL,未知UNKNOWN
   * @param {*} brandId
   * @param {*} brandName
   * @param {*} projectId
   * @param {*} projectName
   * @param {*} alarmStyle
   * @param {*} alarmUsername 负责人名称
   * @returns 
   */
  async insertAlarm(params: any): Promise<any> {
    const { ctx } = this;
    const userInfo = ctx.userInfo;

    //  负责人名称和id
    let _userid = [];
    let _username = [];
    params.alarmUserid.forEach(item => {
      _userid.push(item.userid);
      _username.push(item.name);
    });

    // 创建任务通知
    return await this.RobotAlarmRecordsModel.insertAlarm({
      alarmName: params.alarmName,
      alarmContent: params.alarmContent || "",
      alarmType: params.alarmType,
      alarmTime: params.alarmTime,
      alarmEndtime: params.alarmEndtime,
      alarmUserid: _userid.join(","),
      alarmInner: JSON.stringify(params.alarmInner),
      alarmStatus: "NOT_START",
      createdUserid: userInfo.id,
      createdUsername: userInfo.nick,
      alarmUsername: _username.join(","),
      brandId: params.brandId || null,
      brandName: params.brandName || "",
      projectId: params.projectId || null,
      projectName: params.projectName || "",
      alarmStyle: params.alarmStyle || "",
    });
  }

  /**
   * 更新任务通知
   * @param {*} alarmName 
   * @param {*} alarmContent 
   * @param {*} alarmType 
   * @param {*} alarmTime 
   * @param {*} alarmEndtime 
   * @param {*} alarmUserid 
   * @param {*} alarmInner
   * @param {*} brandId
   * @param {*} brandName
   * @param {*} projectId
   * @param {*} projectName
   * @param {*} alarmStyle
   * @param {*} alarmUsername 负责人名称
   * @returns 
   */
  async updateAlarm(params: any): Promise<any> {
    //  查询当前任务状态
    const task = await this.RobotAlarmRecordsModel.getAlarmById(params.id);
    if (!task || !task.length) {
      throw new httpError.BadRequestError('任务信息不存在，更新失败');
    }
    if (task[0].alarm_status === "START") {
      throw new httpError.BadRequestError('任务信息进行中，更新失败');
    }
    //  负责人名称和id
    let _userid = [];
    let _username = [];
    params.alarmUserid.forEach(item => {
      _userid.push(item.userid);
      _username.push(item.name);
    });

    // 更新任务通知
    return await this.RobotAlarmRecordsModel.updateAlarmById({
      id: params.id,
      alarmName: params.alarmName,
      alarmContent: params.alarmContent || "",
      alarmType: params.alarmType,
      alarmTime: params.alarmTime,
      alarmEndtime: params.alarmEndtime,
      alarmUserid: _userid.join(","),
      alarmInner: JSON.stringify(params.alarmInner),
      alarmUsername: _username.join(","),
      brandId: params.brandId || null,
      brandName: params.brandName || "",
      projectId: params.projectId || null,
      projectName: params.projectName || "",
      alarmStyle: params.alarmStyle || "",
    });
  }

  /**
  * 删除任务通知
  * @param {*} id
  * @returns 
  */
  async delAlarm(params: any): Promise<any> {
    //  查询当前任务状态
    const task = await this.RobotAlarmRecordsModel.getAlarmById(params.id);
    if (task && task[0] && task[0].alarm_status != "START") {
      // 更新任务通知
      return await this.RobotAlarmRecordsModel.delAlarmById(params.id);
    } else {
      throw new httpError.BadRequestError("任务状态为进行中或通知不存在，删除失败！");
    }
  }

  /**
  * 任务通知指定id的通知内容
  * @param {*} id
  * @returns 
  */
  async getAlarmById(params: any): Promise<any> {
    // 查询指定任务通知
    return await this.RobotAlarmRecordsModel.getAlarmById(params.id);
  }

  /**
  * 修改任务通知状态
  * @param {*} id 
  * @param {*} alarmStatus
  * @returns 
  */
  async updateAlarmStatus(params: any): Promise<any> {
    // 修改任务通知状态
    return await this.RobotAlarmRecordsModel.updateAlarmStatus(params);
  }

  /**
  * 通知任务开启和关闭时发送消息
  * @param {*} id
  * @returns 
  */
  async sendAlarmMsg(params: any): Promise<any> {
    // 查询当前通知任务内容
    const alarmInfo = await this.RobotAlarmRecordsModel.getAlarmById(params.id);
    if (!alarmInfo || !alarmInfo.length) return Promise.reject("通知任务不存在");

    if (!alarmInfo[0].alarm_userid) return Promise.reject("通知任务用户信息不能为空");

    let _userIds = alarmInfo[0].alarm_userid.split(",");

    //  日期判断 判断当前日期是不是在开始和结束日期内
    const _nday = moment().format('YYYY-MM-DD');
    const _eday = alarmInfo[0].alarm_endtime;

    //  计算当前日期距离截至日期的倒计时天数
    const daysNum = String(moment(_eday).diff(moment(_nday), 'days'));
    // 发送消息
    const _msgRes = await this.SendDingtalkMsgService.dingtalkMsg({
      id: alarmInfo[0].id,
      alarm_config: alarmInfo[0].alarm_inner,
      alarm_style: alarmInfo[0].alarm_style || "",
      alarm_name: alarmInfo[0].alarm_name,
      alarm_content: alarmInfo[0].alarm_content || "",
      alarm_type: alarmInfo[0].alarm_type,
      user_ids: _userIds,
      msg: params.msg || "",
      days_num: daysNum,
      end_time: alarmInfo[0].alarm_endtime
    });
    //  通知日志存储
    await this.RobotAlarmLogsModel.createAlarmLogs({
      alarmId: alarmInfo[0].id,
      logName: params.msg ? `${alarmInfo[0].alarm_type}-任务通知-${params.msg || ''}` : `${alarmInfo[0].alarm_type}-任务通知`,
      logData: JSON.stringify(_msgRes),
    });
    if (_msgRes && _msgRes.success) return _msgRes;
    return Promise.reject(_msgRes.msg || `钉钉消息发送失败，请检查配置信息。`);
  }

  /**
   * 定时任务执行逻辑
   * 每天10点执行任务通知 发送正在进行中的通知消息至对应的钉钉群或者用户
   */
  async scheduleTasks(): Promise<any> {
    //  查询当前正在进行中的消息信息
    const taskLists = await this.RobotAlarmRecordsModel.getDataByStatus("START");
    let resArr = [];
    if (taskLists && taskLists.length) {
      for (let i = 0; i < taskLists.length; i++) {
        const item = taskLists[i];

        //  计算当前日期距离截至日期的倒计时天数
        const { status, daysNum } = await this.dayCompareSize(item.alarm_time, item.alarm_endtime);
        if (daysNum < 0) {
          //  当前任务时间点已结束 修改状态为已结束
          await this.RobotAlarmRecordsModel.updateAlarmStatus({
            id: item.id, alarmStatus: "END"
          });
          resArr.push({ id: item.id, data: "任务已结束" });
          continue;
        }
        if (!status) {
          resArr.push({ id: item.id, msg: "当前时间未在设置的时间范围内" })
          continue;
        }
        const userIds = item.alarm_userid.split(",");
        if (!userIds || !userIds.length) {
          resArr.push({ id: item.id, msg: "用户信息不存在" });
          continue;
        }
        // 发送消息
        const _msgRes = await this.SendDingtalkMsgService.dingtalkMsg({
          id: item.id,
          alarm_config: item.alarm_inner,
          alarm_style: item.alarm_style || "",
          alarm_name: item.alarm_name,
          alarm_content: item.alarm_content || "",
          alarm_type: item.alarm_type,
          user_ids: userIds,
          msg: "",
          days_num: daysNum,
          end_time: item.alarm_endtime
        });
        //  通知日志存储
        await this.RobotAlarmLogsModel.createAlarmLogs({
          alarmId: item.id,
          logName: `${item.alarm_type}-任务通知`,
          logData: JSON.stringify(_msgRes),
        });
        resArr.push({ id: item.id, data: _msgRes });
      }
    }
    return {
      msg: "定时任务",
      data: resArr
    };
  }

  /**
   * 日期判断 判断当前日期是不是在开始和结束日期内
   * @param {*} day_n    提前通知天数
   * @param {*} e_day    结束时间
   */
  async dayCompareSize(day_n: any, e_day: any): Promise<any> {
    const _nday = moment().format('YYYY-MM-DD');
    const _sday = await this.getNextDate(e_day, -Number(day_n));
    // 当前日期
    const _now = new Date(_nday).getTime();
    // 开始日期
    const _start = new Date(_sday).getTime();
    // 结束日期
    const _end = new Date(e_day).getTime();
    //  距离结束日期天数计算
    const daysNum = moment(e_day).diff(moment(_nday), 'days');

    return { status: (_now >= _start && _now <= _end) ? true : false, daysNum };
  }

  /**
   * JavaScript 获取指定日期的前几天或者后几天的日期
   * @param date {string} 日期 如：2021-06-21
   * @param day {number} 天数 如：1 后几天|-1 前几天，默认后1天
   * @param format {string} 时间格式 如：2021-06-22，默认 -
   * @returns {string}
   */
  async getNextDate(date: any, day = 1, format = "{y}-{m}-{d}"): Promise<any> {
    if (date) {
      const nDate = new Date(date);
      nDate.setDate(nDate.getDate() + day);

      const formatObj = {
        y: nDate.getFullYear(),
        m: nDate.getMonth() + 1,
        d: nDate.getDate(),
      };
      return format.replace(/{([ymd])+}/g, (result, key) => {
        const value = formatObj[key];
        return value.toString().padStart(2, "0");
      });
    } else {
      return Promise.reject("getNextDate:错误的参数");
    }
  }

}